/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stud.cp.user.dbaccess;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import stud.cp.core.dbaccess.DAO;
import stud.cp.core.dbaccess.DAOException;
import stud.cp.user.valueobjects.WeaponType;

/**
 * Класс доступа к таблице с типами оружия.
 * @author Morfant
 */
public class WeaponTypesDAO implements DAO<WeaponType> {

    /**
     * Логгер.
     */
    private static Logger logger = Logger.getLogger("CPTNP");
    /**
     * Список названий колонок таблицы weapon_types.
     */
    private static String[] weaponTypesColumnName = {"weapon_type_id", "name", "description"};
    /**
     * Коннект к базе данных.
     */
    private Connection connection = null;

    /**
     * Конструктор, который создает
     * коннект к базе данных.
     */
    public WeaponTypesDAO(Connection connection) {
        this.connection = connection;
    }

    /**
     * Запрос, позволяющий при выполнении
     * получить полностью данные из таблицы
     * weapon_types.
     * @return Строка запроса.
     */
    private String getQueryForAllWeaponType() {
        StringBuilder query = new StringBuilder();
        query.append("select weapon_type_id,name,description \n");
        query.append("from weapon_types");
        return query.toString();
    }

    /**
     * Метод, который возвращает
     * список значений из таблицы
     * weapon_types.
     * @return Список данных.
     */
    @Override
    public List<WeaponType> getAll() throws DAOException {
        List<WeaponType> data_list = new LinkedList<WeaponType>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllWeaponType());
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new WeaponType(set.getInt(weaponTypesColumnName[0]),
                        set.getString(weaponTypesColumnName[1]),
                        set.getString(weaponTypesColumnName[2])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_weapon_type", ex);
            throw new DAOException("Ошибка получения списка данных", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Запрос, позволяющий получить запись по id.
     * @param id ID
     * @return Запрос.
     */
    private String getQueryForGetById(int id) {
        StringBuilder query = new StringBuilder();

        query.append("SELECT weapon_type_id, name,description \n");
        query.append("FROM weapon_types \n");
        query.append("WHERE weapon_type_id=");
        query.append(id);

        return query.toString();
    }

    /**
     * Метод, позволяющий получить запись
     * по её ID
     * @param id ID
     * @return Данные записи.
     * @throws DAOException
     * <p>
     *  Ошикба доступа к данным.
     * </p>
     */
    @Override
    public WeaponType getById(int id) throws DAOException {
        WeaponType weaponType = null;
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForGetById(id));
            set = prestat.executeQuery();
            if (set.next()) {
                weaponType = new WeaponType(set.getInt(weaponTypesColumnName[0]),
                        set.getString(weaponTypesColumnName[1]),
                        set.getString(weaponTypesColumnName[2]));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety", ex);
            throw new DAOException("Ошибка при создание данных..", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return weaponType;
    }

    /**
     * Запрос на обновление записи в таблице.
     * @param id ID
     * @param name Имя
     * @return Запрос.
     */
    private String getQueryForUpdate(Integer id, String name, String description) {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE weapon_types \n ");
        query.append("SET name='");
        query.append(name);
        query.append("', description='");
        query.append(description);
        query.append("' \n ");
        query.append("WHERE weapon_type_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Метод, отвечающий за обновление данных.
     * @param entry Запись.
     * @throws DAOException Ошибка при обновление данных.
     */
    @Override
    public void update(WeaponType entry) throws DAOException {
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(
                    getQueryForUpdate(
                    entry.getWeapon_type_id(),
                    entry.getName(),
                    entry.getDescription()));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка обновлени данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Зарпос на получения следующего ID.
     * @return Зарпос.
     */
    private String getQueryForSelectNextID() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT weapon_types_seq.NEXTVAL from dual \n");
        return query.toString();
    }

    /**
     * Зарпос на получения максимального id из таблицы.
     * @return Зарпос.
     */
    private String getQueryForSelectMaxId() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT MAX(weapon_type_id) \n");
        query.append("FROM weapon_types");
        return query.toString();
    }

    /**
     * Запрос на добавление
     * новой записи в таблицу.
     * @param id ID
     * @param name Имя
     * @param description Описание.
     * @return Запрос.
     */
    private String getQueryForInsert(Integer id, String name, String description) {
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO weapon_types(weapon_type_id,name,description) \n");
        query.append("VALUES(");
        query.append(id);
        query.append(",'");
        query.append(name);
        query.append("','");
        query.append(description);
        query.append("')");
        return query.toString();
    }

    /**
     * Метод, который создает новую запись в таблице.
     * @param entry Запись.
     * @throws DAOException Ошибка создания новой записи.
     */
    @Override
    public int create(WeaponType entry) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForSelectNextID());
            set = prestat.executeQuery();
            Integer index = null;
            if (set.next()) {
                index = set.getInt(1);
            } else {
                index = 0;
            }
            prestat.close();
            prestat = connection.prepareStatement(getQueryForInsert(
                    index, entry.getName(),
                    entry.getDescription()));
            prestat.executeUpdate();
            return index;
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка при создание записи.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Зарпос на удаление из таблицы
     * записи по id.
     * @param id ID
     * @return Зарпос.
     */
    private String getQueryForDelete(int id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM weapon_types \n");
        query.append("WHERE weapon_type_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Запрос на все оружие
     * относящееся к конкретному типу оружия.
     * @param weapon_type_id ID типа оружия.
     * @return Запрос.
     */
    private String getQueryForWeapon(int weapon_type_id) {
        StringBuilder query = new StringBuilder();
        query.append("select weapon_id \n");
        query.append("from weapons \n");
        query.append("where weapon_type_id=");
        query.append(weapon_type_id);
        return query.toString();
    }

    /**
     * Запрос на все расширения типа
     * относящееся к конкретному типу оружия.
     * @param weapon_type_id ID типа оружия.
     * @return Запрос.
     */
    private String getQueryForPropertyTypeDefsForWeaponType(int weapon_type_id) {
        StringBuilder query = new StringBuilder();
        query.append("select property_type_def_id \n");
        query.append("from property_type_defs \n");
        query.append("where weapon_type_id=");
        query.append(weapon_type_id);
        return query.toString();
    }

    /**
     * Удаление из табилцы
     * property_values.
     * @param weapon_id ID оружия.
     * @return  Зарпос.
     */
    private String getQueryForDeleteFromPropertyValues(int weapon_id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM property_values \n");
        query.append("WHERE weapon_id=");
        query.append(weapon_id);
        return query.toString();
    }

    /**
     * Удаление из табилцы
     * weapon_references.
     * @param weapon_id ID оружия.
     * @return  Зарпос.
     */
    private String getQueryForDeleteFromWeaponReferences(int weapon_id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM weapon_references \n");
        query.append("WHERE weapon_id=");
        query.append(weapon_id);
        query.append("\n OR reference_weapon_id=");
        query.append(weapon_id);
        return query.toString();
    }

    /**
     * Удаление из табилцы
     * weapon_types_properties.
     * @param weapon_type_id ID типа оружия.
     * @return  Зарпос.
     */
    private String getQueryForDeleteFromWeaponTypesProperties(int weapon_type_id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM weapon_types_properties \n");
        query.append("WHERE weapon_type_id=");
        query.append(weapon_type_id);
        return query.toString();
    }

    /**
     * Удаление из табилцы
     * weapons.
     * @param weapon_type_id ID типа оружия.
     * @return  Зарпос.
     */
    private String getQueryForDeleteFromWeapons(int weapon_type_id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM weapons \n");
        query.append("WHERE weapon_type_id=");
        query.append(weapon_type_id);
        return query.toString();
    }

    /**
     * Операция удаления записи из
     * таблицы.
     * @param id Объект, который надо удалить.
     */
    @Override
    public void delete(int id) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForWeapon(id));
            set = prestat.executeQuery();
            List<Integer> data_list = new LinkedList<Integer>();
            while (set.next()) {
                data_list.add(set.getInt(1));
            }
            prestat.close();

            WeaponDAO weaponDAO = new WeaponDAO(connection);
            for (Integer item : data_list) {
                weaponDAO.delete(item);
//                prestat = connection.prepareStatement(getQueryForDeleteFromPropertyValues(item));
//                prestat.executeUpdate();
//                prestat.close();
//                prestat = connection.prepareStatement(getQueryForDeleteFromWeaponReferences(item));
//                prestat.executeUpdate();
//                prestat.close();
            }
            prestat = connection.prepareStatement(getQueryForPropertyTypeDefsForWeaponType(id));
            set = prestat.executeQuery();
            data_list = new LinkedList<Integer>();
            while (set.next()) {
                data_list.add(set.getInt(1));
            }
            prestat.close();
            PropertyTypeDefsDAO propertyTypeDefsDAO = new PropertyTypeDefsDAO(connection);
            for (Integer item : data_list) {
                propertyTypeDefsDAO.delete(item);
            }
//            prestat = connection.prepareStatement(getQueryForDeleteFromWeapons(id));
//            prestat.executeUpdate();
//            prestat.close();
            prestat = connection.prepareStatement(getQueryForDeleteFromWeaponTypesProperties(id));
            prestat.executeUpdate();
            prestat.close();
            prestat = connection.prepareStatement(getQueryForDelete(id));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка удаления данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }
}
